package charts;
import charts.series.Element;
import flash.geom.Point;
import elements.axis.XAxisLabels;

class ObjectCollection
{
	public var sets:Array<Dynamic>; // TODO - find out the actual Type of this thing
	public var groups:Float;
	
	public function ObjectCollection() {
		this.sets = new Array<Dynamic>();
	}
	
	public function add( set:Dynamic ): Void {
		this.sets.push( set );
	}
	
	
	public function get_max_x():Float {
		
		var max:Float = Math.NEGATIVE_INFINITY;

		for( o in this.sets )
			max = Math.max( max, o.get_max_x() );

		return max;
	}
	
	public function get_min_x():Float {
		
		var min:Float = Math.POSITIVE_INFINITY;

		for ( o in this.sets )
			min = Math.min( min, o.get_min_x() );

		return min;
	}
	
	// get x, y co-ords of vals
	public function resize( sc:ScreenCoordsBase ):Void {
		for ( o in this.sets )
			o.resize( sc );
	}
	
	/**
	 * Tell each set to update the tooltip string and
	 * eplace all #x_label# with the label
	 * 
	 * @param	labels
	 */
	public function tooltip_replace_labels( labels:XAxisLabels ):Void {
		for ( o in this.sets )
			o.tooltip_replace_labels( labels );
	}
	
	public function mouse_out():Void {
		for ( s in this.sets )
			s.mouse_out();
	}
	
	
	function closest( x:Float, y:Float ):Element {
		var o:Dynamic;
		var s:Base;
		
		// get closest points from each data set
		var closest:Array = new Array();
		for( s in this.sets )
			closest.push( s.closest( x, y ) );
		
		// find closest point along X axis
		var min:Float = Math.POSITIVE_INFINITY;
		for( o in closest )
			min = Math.min( min, o.distance_x );
			
		//
		// now select all points that are the
		// min (see above) distance along the X axis
		//
		var xx:Dynamic = {element:null, distance_x:Math.POSITIVE_INFINITY, distance_y:Math.POSITIVE_INFINITY };
		for( o in closest ) {
			if( o.distance_x == min )
			{
				// these share the same X position, so choose
				// the closest to the mouse in the Y
				if( o.distance_y < xx.distance_y )
					xx = o;
			}
		}
		
		// pie charts may not return an element
		if( xx.element )
			xx.element.set_tip( true );
			
		return xx.element;
	}
	
	/*
	
	hollow
		line --> ------O---------------O-----
			
				+-----+
				|  B  |
			+-----+     |   +-----+
			|  A  |     |   |  C  +- - -
			|     |     |   |     |  D
			+-----+-----+---+-----+- - -
				1    2
		
	*/
	public function mouse_move( x:Float, y:Float ):Element {
		//
		// is the mouse over, above or below a
		// bar or point? For grouped bar charts,
		// two bars will share an X co-ordinate
		// and be the same distance from the
		// mouse. For example, if the mouse is
		// in position 1 in diagram above. This
		// filters out all items that are not
		// above or below the mouse:
		//
		var e:Element = null;// this.inside__(x, y);
		
		if ( !e )
		{
			//
			// no elements are above or below the mouse,
			// so we select the BEST item to show (mouse
			// is in position 2)
			//
			e = this.closest(x, y);
		}
		
		return e;
	}
	
	
	//
	// Usually this will return an Array of one Element to
	// the Tooltip, but some times 2 (or more) elements will
	// be on top of each other
	//
	public function closest_2( x:Float, y:Float ):Array<Dynamic> {

		var e:Element;
		var s:Base;
		var p:flash.geom.Point;
		
		//
		// get closest points from each data set
		//
		var closest:Array<Dynamic> = new Array();
		for( s in this.sets ) {
			
			var arr:Array = s.closest_2( x, y );
			for( e in arr )
				closest.push( e );
		}
		
		//
		// find closest point along X axis
		// different sets may return elements
		// in different X locations
		//
		var min_x:Float = Math.POSITIVE_INFINITY;
		for( e in closest ) {
			
			p = e.get_mid_point();
			min_x = Math.min( min_x, Math.abs( x - p.x ) );
		}
		
		//
		// filter out the elements that
		// are too far away along the X axis
		//
		var good_x:Array = new Array();
		for( e in closest ) {
			
			p = e.get_mid_point();
			if ( Math.abs( x - p.x ) == min_x )
				good_x.push( e );
		}
		
		//
		// now get min_y from filtered array
		//
		var min_y:Float = Math.POSITIVE_INFINITY;
		for( e in good_x ) {
			
			p = e.get_mid_point();
			min_y = Math.min( min_y, Math.abs( y - p.y ) );
		}
		
		//
		// now filter out any that are not min_y
		//
		var good_x_and_y:Array = new Array();
		for( e in good_x ) {
			
			p = e.get_mid_point();
			if ( Math.abs( y - p.y ) == min_y )
				good_x_and_y.push( e );
		}

		return good_x_and_y;
	}
	
	//
	// find the closest point to the mouse
	//
	public function mouse_move_proximity( x:Float, y:Float ):Array<Dynamic> {
		var e:Element;
		var s:Base;
		var p:flash.geom.Point;
		
		//
		// get closest points from each data set
		//
		var closest:Array<Dynamic> = new Array();
		for( s in this.sets ) {
			
			var arr:Array = s.mouse_proximity( x, y );
			for( e in arr )
				closest.push( e );
		}
		
		//
		// find the min distance to these
		//
		var min_dist:Float = Math.POSITIVE_INFINITY;
		var mouse:flash.geom.Point = new flash.geom.Point(x, y);
		for( e in closest ) {
			min_dist = Math.min( flash.geom.Point.distance(e.get_mid_point(), mouse), min_dist );
		}
		
		// keep these closest elements
		var close:Array = [];
		for( e in closest ) {
			if ( flash.geom.Point.distance(e.get_mid_point(), mouse) == min_dist )
				close.push( e );
		}
		
		return close;
	}
	
	//
	// are we resizing a PIE chart?
	//
	public function has_pie():Bool {
		/// NOTE: stupid code
/*		if ( this.sets.length > 0 && ( this.sets[0] is Pie ) )
			return true;
		else
			return false;*/
		return this.sets.length > 0 && Std.is( this.sets[0], Pie );
	}
	
	/**
	 * To stop memory leaks we explicitly kill all
	 * our children
	 */
	public function die():Void {
		for( o in this.sets )
			o.die();
	}
}
